/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       creature_array_window.h

	$Header: /game/creature_array_window.h $

	$NoKeywords: $

 ************************************************************************/
#ifndef CREATURE_ARRAY_WINDOW_H_INCLUDED
#define CREATURE_ARRAY_WINDOW_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "bitmap_group_ptr.h"
#include "bitmap_layer_ptr.h"
#include "bitmap_layer_window.h"
#include "bitmap_layer_cache_window_ptr.h"
#include "button_ptr.h"
#include "creature_array.h"
#include "game_window.h"
#include "handler.h"
#include "text_window_ptr.h"

// ---------------------------------------------------------------------------
// window for displaying and manipulating lists of creatures
// ---------------------------------------------------------------------------
class t_creature_array_window;
class t_drag_artifact;
class t_drag_creature;
class t_drag_object;

typedef t_handler_2<t_creature_array_window*, int> t_creature_array_handler;

class t_creature_array_window : public t_window
{
public:
	enum t_layout
	{
		k_single_row,
		k_top_row,
		k_bottom_row,
		k_stacked_rows
	};

	// Data for a t_drag_validate_handler
	struct t_drag_drop_validate_data
	{
		t_creature_array_window const * drag_target;
		int								drag_target_slot;
		t_drag_object const *			drag_source;
	};

	// Handler for deciding if a given drag-drop is valid. Set bool to true if
	// acceptable, false if not
	typedef t_handler_2< t_drag_drop_validate_data const &, bool & > t_drag_validate_handler;


	// Data for a t_split_min_max_handler
	struct t_split_min_max_data
	{
		// Incoming data
		t_creature_array_window * window;
		t_creature_array		* left_army;
		int						  left_slot;
		t_creature_array		* right_army;
		int						  right_slot;

		// Output
		int *					  min_left;   // Minimum creatures remaining on the left side of the split dialog
		int *					  min_right;  // Minimum creatures remaining on the right side of the split dialog
	};

	// Handler for setting the range of a split. Leave mins at 1 and 1 if normal
	// split is OK
	typedef t_handler_1< t_split_min_max_data & > t_split_min_max_handler;

	
	t_creature_array_window( t_screen_point const& point, 
		                     t_creature_array* army,
							 t_layout layout, int transfer_cost, t_window* parent,
                             bool accept_foreign_windows = true, bool allow_drags = true );
	~t_creature_array_window();

	void							accept_artifact_drag( t_drag_artifact* drag, int slot_number );
	void							accept_creature_drag( t_drag_creature* drag_creature, int slot_number );
	void							add( t_creature_stack_ptr stack, int slot, int cost,
										 int transfer_charge );
	void							cancel_divide_mode();
	void							changed();
	void							clear_drag_target();
	void							clear_slot( int index );
	void							double_click( int index );
	bool							get_allow_drags() const;
	t_creature_array*				get_army();
	t_creature_array const *		get_army() const;
	t_drag_validate_handler			get_drag_validate_handler() const;
	int								get_frame_height() const;
	int								get_selected_slot() const;
	t_split_min_max_handler			get_split_min_max_handler() const;
	int								get_transfer_charge( int slot ) const;
	int								get_transfer_cost( t_creature_stack const& stack,
													   t_creature_array const& army ) const;
	void							link_selection( t_creature_array_window * linked_window );
	bool							in_divide_mode() const;
	bool							is_slot_highlighted( int slot_number );
	bool							is_valid_drag_drop( t_drag_artifact * drag_artifact, int slot_number );
	bool							is_valid_drag_drop( t_drag_creature * drag_creature, int slot_number );
	void							merge( t_creature_array_window* source, bool move_creatures = true, bool move_live_heroes = true, bool move_dead_heroes = true );
	void							select_creature( int index );
	void							select_first();
	void							select_first_valid( int start_ndx, bool backwards = false );
	void							select_leader();
	bool							select_next();
	bool							select_prev();
	void							set_allow_drags( bool allow_drags );
	void							set_army( t_creature_array* army );
	void							set_change_handler( t_handler handler );
	void							set_disabled( int index, bool disable = true );
	void							set_divide_mode( t_handler const& cancel_func );
	void							set_double_click_handler( t_creature_array_handler handler );
	void							set_drag_validate_handler( t_drag_validate_handler drag_validate_handler );
	void							set_drag_target( int index );
	void							set_highlight( int index, bool highlight );
	void							set_select_handler( t_creature_array_handler handler );
	void							set_selected_slot( int slot );
	void							set_split_min_max_handler( t_split_min_max_handler handler );
	void							swap( t_creature_array_window* source );
    void                            toggle_highlight( int index );
	void							update( bool keep_existing_display = false );
protected:
	enum { k_size = t_creature_array::k_size };

	class t_bar_graph
	{
	public:
		void create( t_bitmap_layer const* bar,    t_bitmap_layer const* border,
			         t_screen_point const& offset, t_window*             parent );
		void set( int value, int max_value );
		void set_visible( bool arg );
	protected:
		t_bitmap_layer_window*  m_border;
		t_bitmap_layer_window*  m_bar;
		int					    m_value;
		int					    m_max_value;
	};

	struct t_creature_windows
	{
		t_bitmap_layer_cache_window_ptr portrait_window;
		t_bitmap_window_ptr				border;
		t_bitmap_window_ptr				selected;
		t_bitmap_window_ptr				disabled;
		t_window_ptr					inset;
		t_text_window_ptr				text;
		t_bar_graph						health_bar;
		t_bar_graph						mana_bar;
		int	                            transfer_charge; // amount if creature was charged
		                                                  // a movement fee for transfer
	};

	// All the windows that are selection-linked together 
	// (That is: selecting any one circle in any of the windows
	// deselects all the other circles in all the other windows)
	class t_linked_windows;
	typedef t_counted_ptr< t_linked_windows > t_linked_windows_ptr;
	friend class t_linked_windows;

	bool			check_transfer_cost( t_creature_stack const& stack, int slot_number, int cost );
	virtual void	on_close();
	bool			split_dialog( t_drag_creature* drag_creature, int slot_number, int cost_in, int cost_out );

    bool                      m_accept_foreign_windows;
	bool					  m_allow_drags;
	t_creature_array*		  m_army;
	int                       m_base_transfer_cost; // cost, in movement points, of transfering
	                                           // a creature from another window.
	t_handler				  m_cancel_divide_func;
	t_handler				  m_change_handler;
	t_mouse_window_ptr		  m_divide_cursor;
	t_bitmap_group_ptr		  m_divide_image;
	t_creature_array_handler  m_double_click_handler;
	t_drag_validate_handler	  m_drag_validate_handler;
	t_bitmap_group_ptr		  m_hero_portraits;
	bool					  m_in_divide_mode;
	t_linked_windows_ptr	  m_linked_windows;
	t_bitmap_group_ptr		  m_rings;
	t_creature_array_handler  m_select_handler;
	int                       m_selected_slot;
	t_split_min_max_handler   m_split_min_max_handler;
	bool                      m_sticky;
	t_creature_windows m_slot[k_size];
};

inline void t_creature_array_window::changed()
{
	m_change_handler();
}

inline bool t_creature_array_window::in_divide_mode() const
{
	return m_in_divide_mode;
}

inline bool t_creature_array_window::get_allow_drags() const
{
	return m_allow_drags;
}

inline t_creature_array* t_creature_array_window::get_army()
{
	return m_army;
}

inline t_creature_array const * t_creature_array_window::get_army() const
{
	return m_army;
}

inline t_creature_array_window::t_drag_validate_handler t_creature_array_window::get_drag_validate_handler() const
{
	return m_drag_validate_handler;
}

inline t_creature_array_window::t_split_min_max_handler t_creature_array_window::get_split_min_max_handler() const
{
	return m_split_min_max_handler;
}

inline int t_creature_array_window::get_transfer_charge( int slot ) const
{
	return m_slot[slot].transfer_charge;
}

inline void t_creature_array_window::set_allow_drags( bool allow_drags )
{
    m_allow_drags = allow_drags;
}

inline void t_creature_array_window::set_change_handler( t_handler handler )
{
	m_change_handler = handler;
}

inline 
void t_creature_array_window::set_double_click_handler( t_creature_array_handler handler )
{
	m_double_click_handler = handler;
}

inline void t_creature_array_window::set_drag_validate_handler( t_drag_validate_handler drag_validate_handler )
{
	m_drag_validate_handler = drag_validate_handler;
}

inline void t_creature_array_window::set_select_handler( t_creature_array_handler handler )
{
	m_select_handler = handler;
}

inline int t_creature_array_window::get_selected_slot() const
{
	return m_selected_slot;
}

inline void	t_creature_array_window::set_selected_slot( int slot )
{
	m_selected_slot = slot;
}

inline void t_creature_array_window::set_split_min_max_handler( t_split_min_max_handler handler )
{
	m_split_min_max_handler = handler;
}

#endif // CREATURE_ARRAY_WINDOW_H_INCLUDED
